package algorithms;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;

import puppy.graph.AgeAggregator;
import puppy.graph.CreateGraphDirected;
import puppy.graph.CreateLM;
import puppy.graph.DeliciousEdge;
import puppy.graph.DeliciousEdgeTransformer;
import puppy.graph.DeliciousNode;
import puppy.graph.DeliciousNodeTransformer;
import util.hashing.Sorting;
import util.ranker.RankingService;
import edu.uci.ics.jung.algorithms.scoring.PageRank;

public class RandomWalkLatentEngine implements RankingService{
	CreateGraphDirected graph = null;
	CreateLM lm = null; 
	double query_total=0;
	
	DeliciousEdgeTransformer edge_transformer = null;
	DeliciousNodeTransformer node_transformer = null;
	AgeAggregator agg = null;
	public double epsilon=0.000001;

	public double alpha=0.2;
	public int max_iterations=5;

	public double n_gram_weight=2;
	public int mimimum_length_ngram=2;

	private int results_printed=100;

	private Float query_threshold_freq=3f;
	

	public RandomWalkLatentEngine(String path, String co_occur, String w_p, String d_p, String z_p, AgeAggregator agg,double alpha,int max_iterations) {
		this.agg= agg;
		this.alpha=alpha;
		this.max_iterations=max_iterations;
		
		graph =new CreateGraphDirected(agg,w_p,d_p,z_p);
	
		graph.initGraph(path);
		//graph.createGraph(path);
		
		initLM(co_occur);
		
		
	}
	public void initLM(String path){
		if(path==null) return;
		
		lm = new CreateLM();
		lm.initLM(path);
	}
	
	
	public float calulateConditionalProb(Hashtable<String,Float>q){
		
		float p=0f;
		
		return p;
		
		
	}
	
	/*public Hashtable<String, Float> generatePossibleTokensNGram(String query_text) {
		Hashtable<String, Float> h = new Hashtable<String, Float>();

		String ngram = query_text.replace(" ", "_");
		String t[] = ngram.split("_");

		if (graph.nodes.containsKey(ngram)) {

			float prior =0;
			h.put(ngram, 0f);

		}

		HashSet<String> tokens = new HashSet<String>();
		for (int i = 0; i < t.length; i++) {

			
			if (i + 2 < t.length) {

				String m = t[i] + "_" + t[i + 1] + "_" + t[i + 2];
				if (graph.nodes.containsKey(m) && !tokens.contains(t[i]) && !tokens.contains(t[i+1]) &&!tokens.contains(t[i+2]) ) {

					tokens.add(t[i]);
					tokens.add(t[i+1]);
					tokens.add(t[i+2]);
					h.put(m, 0f);
				}

			}
			
			
			if (i + 1 < t.length) {

				String m = t[i] + "_" + t[i + 1];
				if (graph.nodes.containsKey(m) && !tokens.contains(t[i]) && !tokens.contains(t[i+1])) {

					tokens.add(t[i]);
					tokens.add(t[i+1]);
					
					h.put(m, 0f);
				}

			}
			if (graph.nodes.containsKey(t[i]) && !tokens.contains(t[i])) {
			
				tokens.add(t[i]);
				
				h.put(t[i], 0f);
			}

			

			

		}
		
		return h;
	}*/
	
	public ArrayList<Entry<String, Float>> performPageRankWithPriors(Hashtable<String,Float>q, String query, int limit){
		
		
		
		//create list of query n_gram phrases
		// star_wars --> star_wars_lego
		// star_wars_lego --> star_wars, star_wars_games, etc
		//q=generatePossibleTokensNGram(query);
		DeliciousNodeTransformer transformer = 
				new DeliciousNodeTransformer( q,agg,graph,lm,query, n_gram_weight,  mimimum_length_ngram);
	
	
	
		edge_transformer = 
				new DeliciousEdgeTransformer(agg);
		
		
		//RandomWalkWIthPriors<DeliciousNode, DeliciousEdge> ranker = 	
	//			new RandomWalkWIthPriors<DeliciousNode,DeliciousEdge>
	//	(graph.graph,edge_transformer,transformer, alpha);
	//	ranker.initModifiers(transformer, edge_transformer);
	
	
	//	System.exit(0);
		 
		 RandomWalkMix<DeliciousNode, DeliciousEdge> ranker = 	
								new RandomWalkMix<DeliciousNode,DeliciousEdge>
						(graph.graph,edge_transformer,transformer, alpha);
		ranker.initModifiers(transformer, edge_transformer);
		 
		ranker.setTolerance(epsilon);
		
		ranker.acceptDisconnectedGraph(true);
		ranker.setMaxIterations(max_iterations);
		
		//ranker.setEdgeWeights(edge_weights)
		//System.out.println("Running page rank.." + "\t"+ q);
		ranker.evaluate();	
		
		Enumeration<String> nodes = graph.nodes.keys();
		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		while (nodes.hasMoreElements()) {
			String node = nodes.nextElement();

			DeliciousNode no = graph.nodes.get(node);

			if (no.getName().equals("") || !no.isTag() || tagInQuery(no.getName(),query)) {
				
				continue;
			}
			
		
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);

		

		}

		Iterator<Entry<String, Float>> tuples = Sorting.getTopN_Tuples(scores, false, 150);
		HashSet<String> temp = new HashSet<String>();
	
		int i=0;
		while (tuples.hasNext() ) {
			Entry<String, Float> t = tuples.next();
			
			if(!wasSuggestionsSeenBefore(temp,t.getKey())){
			i++;
		//	results.add(t);
			if(i<results_printed)
				System.out.println(query+ "\t"+ t.getKey() + "\t" + i +"\t" + t.getValue());
			temp.add(t.getKey());
			}
		}
		
		
		
		//clean modifiers
		tuples=null;
		temp.clear();
		temp=null;
		transformer.clean();
		transformer=null;
		
		
		q.clear();
		q=null;
		
		return null;
	}
	
	
	
	public ArrayList<Entry<String, Float>> performPageRanKAbsorving(Hashtable<String,Float>q, String query, int limit){
		
		
		
		//create list of query n_gram phrases
		// star_wars --> star_wars_lego
		// star_wars_lego --> star_wars, star_wars_games, etc
		//q=generatePossibleTokensNGram(query);

	
		DeliciousNodeTransformer transformer = 
				new DeliciousNodeTransformer(
				 q,agg,graph,lm,query, n_gram_weight,  mimimum_length_ngram);
	
	
	
		edge_transformer = 
				new DeliciousEdgeTransformer(agg);
		
		
		//RandomWalkWIthPriors<DeliciousNode, DeliciousEdge> ranker = 	
	//			new RandomWalkWIthPriors<DeliciousNode,DeliciousEdge>
	//	(graph.graph,edge_transformer,transformer, alpha);
	//	ranker.initModifiers(transformer, edge_transformer);
	
	
	//	System.exit(0);
		 
		 RandomWalkAbsorving<DeliciousNode, DeliciousEdge> ranker = 	
								new RandomWalkAbsorving<DeliciousNode,DeliciousEdge>
						(graph.graph,edge_transformer,transformer, alpha);
		ranker.initModifiers(transformer, edge_transformer,q);
		 
		ranker.setTolerance(epsilon);
		
		ranker.acceptDisconnectedGraph(true);
		ranker.setMaxIterations(max_iterations);
		
		//ranker.setEdgeWeights(edge_weights)
		System.out.println("Running page rank.." + "\t"+ q);
		ranker.evaluate();	
		
		Enumeration<String> nodes = graph.nodes.keys();
		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		while (nodes.hasMoreElements()) {
			String node = nodes.nextElement();

			DeliciousNode no = graph.nodes.get(node);

			if (no.getName().equals("") || !no.isTag() || tagInQuery(no.getName(),query)) {
				
				continue;
			}
			
		
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);

		

		}

		Iterator<Entry<String, Float>> tuples = Sorting.getTopN_Tuples(scores, false, 150);
		HashSet<String> temp = new HashSet<String>();
	
		int i=0;
		while (tuples.hasNext() ) {
			Entry<String, Float> t = tuples.next();
			
			if(!wasSuggestionsSeenBefore(temp,t.getKey())){
			i++;
		//	results.add(t);
			if(i<results_printed)
				System.out.println(query+ "\t"+ t.getKey() + "\t" + i +"\t" + t.getValue());
			temp.add(t.getKey());
			}
		}
		
		
		
		//clean modifiers
		tuples=null;
		temp.clear();
		temp=null;
		transformer.clean();
		transformer=null;
		
		
		q.clear();
		q=null;
		
		return null;
	}
	
	
private boolean wasSuggestionsSeenBefore(HashSet<String> temp, String key) {
		// TODO Auto-generated method stub

		if(temp.contains(key+ "s")) return true;
		
		if(temp.contains(key.substring(0,key.length()-1))) return true;
	
		return false;
	}


public Hashtable<String,Float> rerankQueryRepresentation(Hashtable<String,Float>q, int limit){
	Hashtable<String,Float> r= new Hashtable<String,Float>();
	Iterator<String> temp = Sorting.getTopN(q, false,limit);
	while(temp.hasNext()){
		String key =temp.next();
		
		r.put(key, q.get(key));
	}
	return r;
	
}

public ArrayList<Entry<String, Float>> performPageRank(Hashtable<String,Float>q, Hashtable<String, Float> q_topics,String query, int limit){

	
	
	/**
	 * Change this back
	 * 
	 * 
	 */

	//q=rerankQueryRepresentation(q, 10);
	
	
		DeliciousNodeTransformer transformer = 
			new DeliciousNodeTransformer( q,q_topics,agg,graph, lm,query, n_gram_weight,  mimimum_length_ngram);
	
		DeliciousEdgeTransformer edge_transformer = new DeliciousEdgeTransformer(agg);
		
				
		RandomWalkLatent<DeliciousNode, DeliciousEdge> ranker = 	
				new RandomWalkLatent<DeliciousNode,DeliciousEdge>(graph.graph,transformer, alpha);
	
		ranker.initModifiers(transformer, edge_transformer);
		
		ranker.setTolerance(epsilon);
		
		ranker.acceptDisconnectedGraph(true);
		ranker.setMaxIterations(max_iterations);
		
		//ranker.setEdgeWeights(edge_weights)
		//System.out.println("Running page rank..");
		ranker.evaluate();	
		
		Enumeration<String> nodes = graph.nodes.keys();
		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		while (nodes.hasMoreElements()) {
			String node = nodes.nextElement();

			DeliciousNode no = graph.nodes.get(node);

			if (no.getName().equals("") || !no.isTag() || tagInQuery(no.getName(),query)) {
				
				continue;
			}
			
		
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);

		

		}

		Iterator<Entry<String, Float>> tuples = Sorting.getTopN_Tuples(scores, false, 150);
		ArrayList<Entry<String, Float>> results  = new ArrayList<Entry<String, Float>>();
		int i=0;
		while (tuples.hasNext() ) {
			Entry<String, Float> t = tuples.next();
			i++;
			results.add(t);
			if(i<results_printed)
			System.out.println(query+ "\t"+ t.getKey() + "\t" + i +"\t" + t.getValue());
		}
		
		tuples=null;
		return results;
	}



 public Hashtable<String,Float> reRankQueryTerms(Hashtable<String,Float> q, String query){
	 
	 Hashtable<String,Float> re = new Hashtable<String,Float>();
	 
	 Enumeration<String> keys = q.keys();
	 
	 while(keys.hasMoreElements()){
		 
		 
	 }
	 
	 return re;
	 
	 
 }
	private boolean tagInQuery(String name, String query) {
		// TODO Auto-generated method stub

		//example tag star   query star_wars
		
		query = query.replaceAll("_", " ");
		
		name = name.replaceAll("_", " ");
		
		String[] query_tokens = query.split(" ");
		String[] tag_tokens = name.split(" ");
		
		
		
		if(name.contains(query) && name.length()>query.length()) return false;
		
		if(query.equals(name)){
			
			
			return true;
	
		} 
		
		int matches=0;
		for(int i=0; i< tag_tokens.length; i++){
			
			for(int j=0; j<query_tokens.length; j++){
				
				if(tag_tokens[i].equals(query_tokens[j])){
				
					matches++;
					
				}
			}
		}
		
	
		if(matches>=tag_tokens.length) return true;
		
		return false;
	}
	
	

	public void performPageRank_temp() {

		PageRank<DeliciousNode, DeliciousEdge> ranker = new PageRank<DeliciousNode, DeliciousEdge>(
				graph.graph, 0.15);
		
		
		ranker.acceptDisconnectedGraph(true);
		//ranker.setMaxIterations(1000);
		System.out.println(ranker.getIterations());
		//ranker.setEdgeWeights(edge_weights)
		System.out.println("Running page rank..");
		ranker.evaluate();	
		
		Enumeration<String> nodes = graph.nodes.keys();
		Hashtable<String, Float> scores = new Hashtable<String, Float>();
		while (nodes.hasMoreElements()) {
			String node = nodes.nextElement();

			DeliciousNode no = graph.nodes.get(node);

			if (no.getName().equals("")) {
				continue;
			}
			double s = ranker.getVertexScore(no);
			scores.put(no.getName(), (float) s);

			// System.out.println("The PageRank score of " + no + " is: " + );

		}

		Iterator<Entry<String, Float>> tuples = Sorting.sortHashNumericValues(
				scores, true);
		while (tuples.hasNext()) {
			Entry<String, Float> t = tuples.next();
			System.out.println(t.getKey() + "\t" + t.getValue());
		}

	}

	
	
	
	public Hashtable<String,Float> calculateQueryRatios(Hashtable<String, Float> q){
		
		Hashtable<String, Float> qq= new Hashtable<String, Float> ();
		
		
		Enumeration<String> keys = q.keys();
		float total=0.0f;
		while(keys.hasMoreElements()){
			String element  = keys.nextElement();
			
			if(element.contains("school")){
				
				
			//	System.out.println(graph.nodes.containsKey(element) + "---\t "+ element);
			}
			if(graph.nodes.containsKey(element)){
			total= total+ q.get(element);
			}
			
		}
		
		keys=q.keys();
		while(keys.hasMoreElements()){
			String tag= keys.nextElement();
			if(graph.nodes.containsKey(tag)){
				if (q.get(tag)>=query_threshold_freq){
			//	if(tag.equals("characterized")){System.out.println("aqui si estuvo characterizeds " );}
				qq.put(tag, q.get(tag)/total);		
				}
			}
			
			
		//	System.out.println(tag + "\t"+ qq.get(tag));
		}
//		System.out.println( q+"\t"+ qq);
		return qq;
	}	
	@Override
	public ArrayList<Entry<String, Float>> rankQuery(
			String query, Hashtable<String, Float> q, int limit) {
		
		
	return null;
	
	//	return performPageRanKAbsorving(qq,query,limit);
		//return null;
	}

	@Override
	public ArrayList<Entry<String, Float>> rankQuery(String query, int limit) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ArrayList<Entry<String, Float>> rankQuery(String query,
			Hashtable<String, Float> q, Hashtable<String, Float> q_topics,
			int limit) {
		Hashtable<String, Float> qq = calculateQueryRatios(q);
		// TODO Auto-generated method stub
		System.out.println(query + "\t" + qq);
		return performPageRank(qq,q_topics,query,limit);
	
	}

	
}
